package com.cipe.cmrs.helper;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;

import com.cipe.cmrs.bean.PaymentRequestLineItemBean;
import com.cipe.cmrs.model.Cipeproject;
import com.cipe.cmrs.model.view.ProjectPaymentView;
import com.cipe.cmrs.util.DateUtil2;

@Component
public class PaymentHelper {
    private static final int PARTNER_OVER_GRACE_PERIOD = 90;
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    protected MessageSourceAccessor messageSourceAccessor;

    public String getText(String msgKey) {
        return messageSourceAccessor.getMessage(msgKey);
    }

    public boolean hasData(List<PaymentRequestLineItemBean> items) {
        for (PaymentRequestLineItemBean item : items) {
            if (hasData(item)) {
                return true;
            }
        }
        return false;
    }

    public boolean hasData(PaymentRequestLineItemBean bean) {
        logger.debug("Account Id = " + bean.getAccountCodeId());
        logger.debug("CipePrj Id = " + bean.getCipeProjectId());
        Integer acId = bean.getAccountCodeId();
        Integer ciId = bean.getCipeProjectId();
        return acId != null && acId > 0 && ciId != null && ciId > 0;
    }

    public BigDecimal getTotalAmount(List<PaymentRequestLineItemBean> items) {
        BigDecimal result = BigDecimal.ZERO;
        for (PaymentRequestLineItemBean item : items) {
            if (hasData(item)) {
                result = result.add(item.getAmount());
            }
        }
        return result;
    }

    public boolean canAcceptPayment(ProjectPaymentView pr) {
        String active = getText("statusname.status.project.active");
        String closed = getText("statusname.status.project.over");

        String over = getText("statusname.status.project.over");
        String partner = getText("projecttype.partner");

        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, -30);

        int endDateInterval = 0;
        if (pr.getProjectEndDate() != null) {
            endDateInterval = DateUtil2.INSTANCE.getDateInterval(pr.getProjectEndDate(), new Date());
        }
        return (active.equals(pr.getStatus()) && pr.getRemainingFundsPRExcluded() != null && pr.getRemainingFundsPRExcluded()
            .compareTo(BigDecimal.ZERO) > 0)
            || (active.equalsIgnoreCase(pr.getStatus()) && BooleanUtils.isTrue(pr.getBudgetOverride()))
            || (closed.equalsIgnoreCase(pr.getStatus()) && pr.getRemainingFundsPRExcluded() != null
                && pr.getRemainingFundsPRExcluded().compareTo(BigDecimal.ZERO) > 0 && BooleanUtils.isTrue(pr.getStatusOverride()))
            || (closed.equalsIgnoreCase(pr.getStatus()) && pr.getRemainingFundsPRExcluded() != null
                && pr.getRemainingFundsPRExcluded().compareTo(BigDecimal.ZERO) < 1 && BooleanUtils.isTrue(pr.getStatusOverride()) && BooleanUtils
                    .isTrue(pr.getBudgetOverride()))
            // Status = 'Over' && is partner && project end date is less than or
            // equal to 90 days from current date && has remaining funds
            || (over.equalsIgnoreCase(pr.getStatus()) && partner.equalsIgnoreCase(pr.getProjectTypeDesc()))
            && endDateInterval <= PARTNER_OVER_GRACE_PERIOD
            && pr.getRemainingFundsPRExcluded() != null && pr.getRemainingFundsPRExcluded().compareTo(BigDecimal.ZERO) > 0;
    }

    public void checkForError(Errors errors, BigDecimal remainingFunds, Cipeproject project) {
        StringBuilder stringBuilder = new StringBuilder();

        String over = getText("statusname.status.project.over");
        String partner = getText("projecttype.partner");

        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, -30);

        String status = project.getCipeprojectstatus() != null ? project.getCipeprojectstatus().getDisplayName() : "";
        String projectType = project.getCipeprojecttype() != null ? project.getCipeprojecttype().getDisplayName() : "";

        Integer endDateInterval = 0;
        if (project.getProjectEndDate() != null) {
            endDateInterval = DateUtil2.INSTANCE.getDateInterval(project.getProjectEndDate(), new Date());
        }

        if ((over.equalsIgnoreCase(status) && partner.equalsIgnoreCase(projectType))) {
            if (endDateInterval > PARTNER_OVER_GRACE_PERIOD) {
                stringBuilder.append("You are trying to apply a payment to project ID " + project.getProjectID() != null ? project
                    .getProjectID() : " ");
                stringBuilder.append(", titled \"" + project.getProjectTitle() + "\" ");
                stringBuilder.append("which has had a status of \"" + status + "\" ");
                stringBuilder.append("for greater than " + endDateInterval + " days. ");
                stringBuilder.append("This is not allowed. Please contact the Grants Manager "
                    + "or the Program Manager of this project for assistance.");
                errors.reject("error.payment.project.over30days.enddate",
                    new String[]{ project.getProjectID() != null ? project.getProjectID() : " ", project.getProjectTitle(),
                        project.getCipeprojectstatus().getDisplayName(), endDateInterval.toString() }, stringBuilder.toString());
            } else if (remainingFunds.compareTo(BigDecimal.ZERO) < 0) {
                String projectDisplayName = project.getProjectID() != null ? "Project # " + project.getProjectID() : " " + " ("
                    + project.getProjectTitle() + ")";
                stringBuilder.append("You are trying to apply a payment to " + projectDisplayName);
                stringBuilder.append(" which has a status of " + status);
                stringBuilder.append(". This is not allowed. Please contact the Grants Manager "
                    + "or the Program Manager of this project for assistance.");
                errors.reject("error.payment.project.notallowed", new String[]{ projectDisplayName,
                    " that does not have funds available", project.getCipeprojectstatus().getDisplayName() }, stringBuilder.toString());
            }
        } else if (!validateOverrides(remainingFunds, project)) {
            String projectDisplayName = project.getProjectID() != null ? "Project # " + project.getProjectID() : " " + " ("
                + project.getProjectTitle() + ")";
            stringBuilder.append("You are trying to apply a payment to " + projectDisplayName);
            stringBuilder.append(" which has a status of " + status);
            stringBuilder.append(". This is not allowed. Please contact the Grants Manager "
                + "or the Program Manager of this project for assistance.");
            errors.reject("error.payment.project.notallowed", new String[]{ projectDisplayName, "",
                project.getCipeprojectstatus().getDisplayName() }, stringBuilder.toString());
        }
    }

    private boolean validateOverrides(BigDecimal remainingFunds, Cipeproject project) {
        String active = getText("statusname.status.project.active");
        String closed = getText("statusname.status.project.over");
        String status = project.getCipeprojectstatus() != null ? project.getCipeprojectstatus().getDisplayName() : "";
        boolean budgetOverride = BooleanUtils.toBoolean(project.getOverride());
        boolean statusOverride = BooleanUtils.toBoolean(project.getStatusoverride());

        return (active.equals(status) && remainingFunds.compareTo(BigDecimal.ZERO) >= 0)
            || (active.equalsIgnoreCase(status) && budgetOverride)
            || (closed.equalsIgnoreCase(status) && remainingFunds.compareTo(BigDecimal.ZERO) >= 0 && statusOverride)
            || (closed.equalsIgnoreCase(status) && remainingFunds.compareTo(BigDecimal.ZERO) < 1 && statusOverride && budgetOverride);
    }
}
